Micron Document
🎖️GitЯра🎖️

Node / meshtastic / Meshtastic-Android / files / obtainium / generate-links.py

Displaying Raw • Download

obtainium/generate-links.py claude/node-database-export-f2364b (dfba71a2) Text, 16.02 KB

T8b949e#!/usr/bin/env python3
T8b949e"""Generate the Obtainium artifacts from one source of truth.

This script owns:

1. the one-tap deep-link tables in the project README and the developer guide,
2. the per-flavor Obtainium import files in this directory, and
3. with --refresh, the "currently published" channel table in the guide.

Two kinds of staleness, two modes:

python3 obtainium/generate-links.py # write offline targets
python3 obtainium/generate-links.py --check # verify offline targets, exit 1 on drift
python3 obtainium/generate-links.py --refresh # + hit the releases API (network)

-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely-check is deterministic and offline: the links and import files derive purely
from CHANNELS x FLAVORS, so they can only drift when a commit changes them. That
is a pull-request concern.

-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel-refresh is the part that goes stale on its own. It resolves each channel
against the live GitHub releases and asserts every `apkFilterRegEx` still matches
the assets our release workflows actually publish — so renaming a release asset
fails loudly here instead of silently breaking every user's update check. It also
records which channels are currently published, which changes as builds are
promoted. That is a scheduled concern; see scheduled-updates.yml.

`com.geeksville.mesh.json` is deliberately NOT generated here: it is a
byte-identical mirror of what we submitted to apps.obtainium.imranr.dev and is
maintained by hand alongside that PR.
"""

Tff7b72import T7ee787argparse
Tff7b72import T7ee787json
Tff7b72import T7ee787os
Tff7b72import T7ee787re
Tff7b72import T7ee787sys
Tff7b72import T7ee787urllibT7ee787.T7ee787error
Tff7b72import T7ee787urllibT7ee787.T7ee787request
Tff7b72from T7ee787pathlib Tff7b72import Te6edf3Path
Tff7b72from T7ee787urllibT7ee787.T7ee787parse Tff7b72import Te6edf3quote

Te6edf3REPO_URL Tff7b72= Ta5d6ff"Ta5d6ffhttps://github.com/meshtastic/Meshtastic-AndroidTa5d6ff"
Te6edf3REDIRECT Tff7b72= Ta5d6ff"Ta5d6ffhttps://apps.obtainium.imranr.dev/redirect.html?r=Ta5d6ff"

Te6edf3REPO_ROOT Tff7b72= Te6edf3PathTb4b4b4(Tff7b72__file__Tb4b4b4)Tff7b72.Td2a8ffresolveTb4b4b4(Tb4b4b4)Tff7b72.Td2a8ffparentTff7b72.Td2a8ffparent
Te6edf3DOC Tff7b72= Te6edf3REPO_ROOT Tff7b72/ Ta5d6ff"Ta5d6ffdocs/en/developer/test-builds.mdTa5d6ff"
Te6edf3README Tff7b72= Te6edf3REPO_ROOT Tff7b72/ Ta5d6ff"Ta5d6ffREADME.mdTa5d6ff"
Te6edf3OBTAINIUM_DIR Tff7b72= Te6edf3REPO_ROOT Tff7b72/ Ta5d6ff"Ta5d6ffobtainiumTa5d6ff"

Te6edf3BEGIN Tff7b72= Ta5d6ff"Ta5d6ff<!-- BEGIN GENERATED LINKS: obtainium/generate-links.py -->Ta5d6ff"
Te6edf3END Tff7b72= Ta5d6ff"Ta5d6ff<!-- END GENERATED LINKS -->Ta5d6ff"

Te6edf3STATUS_BEGIN Tff7b72= Ta5d6ff"Ta5d6ff<!-- BEGIN GENERATED STATUS: obtainium/generate-links.py --refresh -->Ta5d6ff"
Te6edf3STATUS_END Tff7b72= Ta5d6ff"Ta5d6ff<!-- END GENERATED STATUS -->Ta5d6ff"

Te6edf3RELEASES_API Tff7b72= Ta5d6ff"Ta5d6ffhttps://api.github.com/repos/meshtastic/Meshtastic-Android/releases?per_page=100Ta5d6ff"

T8b949e# The developer guide documents every channel; the project README only carries
T8b949e# the two channels a normal user should be choosing between.
Te6edf3README_CHANNELS Tff7b72= Tb4b4b4(Ta5d6ff"Ta5d6ffstableTa5d6ff"Tb4b4b4, Ta5d6ff"Ta5d6ffopenTa5d6ff"Tb4b4b4)

T8b949e# Release assets are androidApp-<flavor>[-<abi>]-release.apk; snapshot builds
T8b949e# attach androidApp-<flavor>-<abi>-debug-<versionCode>.apk instead. The google
T8b949e# flavor ships a single universal release APK, so it needs no arch filter; the
T8b949e# fdroid flavor is split per ABI and lets Obtainium's arch filter choose.
Te6edf3FLAVORS Tff7b72= Tb4b4b4{
Ta5d6ff"Ta5d6ffgoogleTa5d6ff"Tb4b4b4: Tb4b4b4{
Ta5d6ff"Ta5d6fflabelTa5d6ff"Tb4b4b4: Ta5d6ff"Ta5d6ffgoogleTa5d6ff"Tb4b4b4,
Ta5d6ff"Ta5d6ffrelease_apkTa5d6ff"Tb4b4b4: Tb4b4b4{Ta5d6ff"Ta5d6ffapkFilterRegExTa5d6ff"Tb4b4b4: Ta5d6ffrTa5d6ff"Ta5d6ffgoogle-releaseTa5d6ff\Ta5d6ff.apk$Ta5d6ff"Tb4b4b4}Tb4b4b4,
Ta5d6ff"Ta5d6ffdebug_apkTa5d6ff"Tb4b4b4: Tb4b4b4{
Ta5d6ff"Ta5d6ffapkFilterRegExTa5d6ff"Tb4b4b4: Ta5d6ffrTa5d6ff"Ta5d6ffgoogle-.*-debug-Ta5d6ff\Ta5d6ffd+Ta5d6ff\Ta5d6ff.apk$Ta5d6ff"Tb4b4b4,
Ta5d6ff"Ta5d6ffautoApkFilterByArchTa5d6ff"Tb4b4b4: Tff7b72TrueTb4b4b4,
Tb4b4b4}Tb4b4b4,
Ta5d6ff"Ta5d6ffdebug_idTa5d6ff"Tb4b4b4: Ta5d6ff"Ta5d6ffcom.geeksville.mesh.google.debugTa5d6ff"Tb4b4b4,
Tb4b4b4}Tb4b4b4,
Ta5d6ff"Ta5d6fffdroidTa5d6ff"Tb4b4b4: Tb4b4b4{
Ta5d6ff"Ta5d6fflabelTa5d6ff"Tb4b4b4: Ta5d6ff"Ta5d6fffdroidTa5d6ff"Tb4b4b4,
Ta5d6ff"Ta5d6ffrelease_apkTa5d6ff"Tb4b4b4: Tb4b4b4{
Ta5d6ff"Ta5d6ffapkFilterRegExTa5d6ff"Tb4b4b4: Ta5d6ffrTa5d6ff"Ta5d6fffdroid-.*-releaseTa5d6ff\Ta5d6ff.apk$Ta5d6ff"Tb4b4b4,
Ta5d6ff"Ta5d6ffautoApkFilterByArchTa5d6ff"Tb4b4b4: Tff7b72TrueTb4b4b4,
Tb4b4b4}Tb4b4b4,
Ta5d6ff"Ta5d6ffdebug_apkTa5d6ff"Tb4b4b4: Tb4b4b4{
Ta5d6ff"Ta5d6ffapkFilterRegExTa5d6ff"Tb4b4b4: Ta5d6ffrTa5d6ff"Ta5d6fffdroid-.*-debug-Ta5d6ff\Ta5d6ffd+Ta5d6ff\Ta5d6ff.apk$Ta5d6ff"Tb4b4b4,
Ta5d6ff"Ta5d6ffautoApkFilterByArchTa5d6ff"Tb4b4b4: Tff7b72TrueTb4b4b4,
Tb4b4b4}Tb4b4b4,
Ta5d6ff"Ta5d6ffdebug_idTa5d6ff"Tb4b4b4: Ta5d6ff"Ta5d6ffcom.geeksville.mesh.fdroid.debugTa5d6ff"Tb4b4b4,
Tb4b4b4}Tb4b4b4,
Tb4b4b4}

Te6edf3RELEASE_ID Tff7b72= Ta5d6ff"Ta5d6ffcom.geeksville.meshTa5d6ff"

T8b949e# Every non-debug channel is RELEASE_ID, so only one of them can be tracked at a
T8b949e# time. `debug` marks the snapshot channel, which gets its own application ID.
Te6edf3CHANNELS Tff7b72= Tb4b4b4[
Tb4b4b4{Ta5d6ff"Ta5d6ffkeyTa5d6ff"Tb4b4b4: Ta5d6ff"Ta5d6ffstableTa5d6ff"Tb4b4b4, Ta5d6ff"Ta5d6fflabelTa5d6ff"Tb4b4b4: Ta5d6ff"Ta5d6ffStableTa5d6ff"Tb4b4b4, Ta5d6ff"Ta5d6ffnameTa5d6ff"Tb4b4b4: Ta5d6ff"Ta5d6ffMeshtasticTa5d6ff"Tb4b4b4, Ta5d6ff"Ta5d6ffsettingsTa5d6ff"Tb4b4b4: Tb4b4b4{Tb4b4b4}Tb4b4b4}Tb4b4b4,
Tb4b4b4{
Ta5d6ff"Ta5d6ffkeyTa5d6ff"Tb4b4b4: Ta5d6ff"Ta5d6ffopenTa5d6ff"Tb4b4b4,
Ta5d6ff"Ta5d6fflabelTa5d6ff"Tb4b4b4: Ta5d6ff"Ta5d6ffOpen betaTa5d6ff"Tb4b4b4,
Ta5d6ff"Ta5d6ffnameTa5d6ff"Tb4b4b4: Ta5d6ff"Ta5d6ffMeshtastic BetaTa5d6ff"Tb4b4b4,
Ta5d6ff"Ta5d6ffsettingsTa5d6ff"Tb4b4b4: Tb4b4b4{Ta5d6ff"Ta5d6ffincludePrereleasesTa5d6ff"Tb4b4b4: Tff7b72TrueTb4b4b4, Ta5d6ff"Ta5d6fffilterReleaseTitlesByRegExTa5d6ff"Tb4b4b4: Ta5d6ff"Ta5d6ff-openTa5d6ff"Tb4b4b4}Tb4b4b4,
Tb4b4b4}Tb4b4b4,
Tb4b4b4{
Ta5d6ff"Ta5d6ffkeyTa5d6ff"Tb4b4b4: Ta5d6ff"Ta5d6ffclosedTa5d6ff"Tb4b4b4,
Ta5d6ff"Ta5d6fflabelTa5d6ff"Tb4b4b4: Ta5d6ff"Ta5d6ffClosed betaTa5d6ff"Tb4b4b4,
Ta5d6ff"Ta5d6ffnameTa5d6ff"Tb4b4b4: Ta5d6ff"Ta5d6ffMeshtastic AlphaTa5d6ff"Tb4b4b4,
Ta5d6ff"Ta5d6ffsettingsTa5d6ff"Tb4b4b4: Tb4b4b4{Ta5d6ff"Ta5d6ffincludePrereleasesTa5d6ff"Tb4b4b4: Tff7b72TrueTb4b4b4, Ta5d6ff"Ta5d6fffilterReleaseTitlesByRegExTa5d6ff"Tb4b4b4: Ta5d6ff"Ta5d6ff-closedTa5d6ff"Tb4b4b4}Tb4b4b4,
Tb4b4b4}Tb4b4b4,
Tb4b4b4{
Ta5d6ff"Ta5d6ffkeyTa5d6ff"Tb4b4b4: Ta5d6ff"Ta5d6ffbleedingTa5d6ff"Tb4b4b4,
Ta5d6ff"Ta5d6fflabelTa5d6ff"Tb4b4b4: Ta5d6ff"Ta5d6ffBleeding edge (newest promoted test build)Ta5d6ff"Tb4b4b4,
Ta5d6ff"Ta5d6ffnameTa5d6ff"Tb4b4b4: Ta5d6ff"Ta5d6ffMeshtastic BetaTa5d6ff"Tb4b4b4,
Ta5d6ff"Ta5d6ffsettingsTa5d6ff"Tb4b4b4: Tb4b4b4{
Ta5d6ff"Ta5d6ffincludePrereleasesTa5d6ff"Tb4b4b4: Tff7b72TrueTb4b4b4,
Ta5d6ff"Ta5d6fffilterReleaseTitlesByRegExTa5d6ff"Tb4b4b4: Ta5d6ff"Ta5d6ff-(closed|open)Ta5d6ff"Tb4b4b4,
Tb4b4b4}Tb4b4b4,
Tb4b4b4}Tb4b4b4,
Tb4b4b4{
Ta5d6ff"Ta5d6ffkeyTa5d6ff"Tb4b4b4: Ta5d6ff"Ta5d6ffsnapshotTa5d6ff"Tb4b4b4,
Ta5d6ff"Ta5d6fflabelTa5d6ff"Tb4b4b4: Ta5d6ff"Ta5d6ffSnapshot (latest commit on `main`)Ta5d6ff"Tb4b4b4,
Ta5d6ff"Ta5d6ffnameTa5d6ff"Tb4b4b4: Ta5d6ff"Ta5d6ffMeshtastic SnapshotTa5d6ff"Tb4b4b4,
Ta5d6ff"Ta5d6ffdebugTa5d6ff"Tb4b4b4: Tff7b72TrueTb4b4b4,
Ta5d6ff"Ta5d6ffsettingsTa5d6ff"Tb4b4b4: Tb4b4b4{
Ta5d6ff"Ta5d6ffincludePrereleasesTa5d6ff"Tb4b4b4: Tff7b72TrueTb4b4b4,
Ta5d6ff"Ta5d6fffilterReleaseTitlesByRegExTa5d6ff"Tb4b4b4: Ta5d6ff"Ta5d6ff^SnapshotTa5d6ff"Tb4b4b4,
Ta5d6ff"Ta5d6ffuseLatestAssetDateAsReleaseDateTa5d6ff"Tb4b4b4: Tff7b72TrueTb4b4b4,
T8b949e# The tag never moves off "snapshot", so the release date is the only
T8b949e# thing that changes between builds.
Ta5d6ff"Ta5d6ffversionDetectionTa5d6ff"Tb4b4b4: Tff7b72FalseTb4b4b4,
Ta5d6ff"Ta5d6ffreleaseDateAsVersionTa5d6ff"Tb4b4b4: Tff7b72TrueTb4b4b4,
Tb4b4b4}Tb4b4b4,
Tb4b4b4}Tb4b4b4,
Tb4b4b4]

T8b949e# What each per-flavor import file carries.
T8b949e#
T8b949e# Release builds of both flavors are RELEASE_ID, so an import file can only ever
T8b949e# carry ONE of them — Obtainium's import calls saveApps() keyed by id, and a
T8b949e# second entry with the same id silently overwrites the first. That is why the
T8b949e# flavor choice is expressed as two separate files, and why the beta channels
T8b949e# (also RELEASE_ID) are left to the deep links rather than bundled here.
T8b949e#
T8b949e# Debug builds are the exception: they carry a per-flavor `.debug` suffix, so
T8b949e# both snapshots are genuinely distinct apps and every file ships both.
Te6edf3EXPORT_RELEASE_CHANNEL Tff7b72= Ta5d6ff"Ta5d6ffstableTa5d6ff"
Te6edf3EXPORT_DEBUG_CHANNELS Tff7b72= Tb4b4b4(Ta5d6ff"Ta5d6ffsnapshotTa5d6ff"Tb4b4b4,Tb4b4b4)


Tff7b72def Td2a8ffconfig_forTb4b4b4(Te6edf3channelTb4b4b4, Te6edf3flavor_keyTb4b4b4)Tb4b4b4:
T8b949e"""Build one Obtainium app config for a channel/flavor pair."""
Te6edf3flavor Tff7b72= Te6edf3FLAVORSTb4b4b4[Te6edf3flavor_keyTb4b4b4]
Te6edf3is_debug Tff7b72= Te6edf3channelTff7b72.Td2a8ffgetTb4b4b4(Ta5d6ff"Ta5d6ffdebugTa5d6ff"Tb4b4b4, Tff7b72FalseTb4b4b4)
Te6edf3settings Tff7b72= Tffa657dictTb4b4b4(Te6edf3channelTb4b4b4[Ta5d6ff"Ta5d6ffsettingsTa5d6ff"Tb4b4b4]Tb4b4b4)
Te6edf3settingsTff7b72.Td2a8ffupdateTb4b4b4(Te6edf3flavorTb4b4b4[Ta5d6ff"Ta5d6ffdebug_apkTa5d6ff"Tb4b4b4] Tff7b72if Te6edf3is_debug Tff7b72else Te6edf3flavorTb4b4b4[Ta5d6ff"Ta5d6ffrelease_apkTa5d6ff"Tb4b4b4]Tb4b4b4)
T8b949e# Flavor-suffix only the snapshots. Both debug flavors can coexist, so their
T8b949e# labels have to disambiguate; a release entry is always singular, so
T8b949e# "Meshtastic" beats branding it with a build-flavor suffix forever.
Te6edf3name Tff7b72= Ta5d6fffTa5d6ff"Tffd700{Te6edf3channelTb4b4b4[Ta5d6ff'Ta5d6ffnameTa5d6ff'Tb4b4b4]Tffd700}Ta5d6ff (Tffd700{Te6edf3flavorTb4b4b4[Ta5d6ff'Ta5d6fflabelTa5d6ff'Tb4b4b4]Tffd700}Ta5d6ff)Ta5d6ff" Tff7b72if Te6edf3is_debug Tff7b72else Te6edf3channelTb4b4b4[Ta5d6ff"Ta5d6ffnameTa5d6ff"Tb4b4b4]
T8b949e# appName is the only reliable label: App.finalName is
T8b949e# `additionalSettings['appName'] ?? name`, and Obtainium otherwise falls back
T8b949e# to the installed app's own label (a debug build shows up as "Google Debug").
Te6edf3settingsTb4b4b4[Ta5d6ff"Ta5d6ffappNameTa5d6ff"Tb4b4b4] Tff7b72= Te6edf3name
Tff7b72return Tb4b4b4{
Ta5d6ff"Ta5d6ffidTa5d6ff"Tb4b4b4: Te6edf3flavorTb4b4b4[Ta5d6ff"Ta5d6ffdebug_idTa5d6ff"Tb4b4b4] Tff7b72if Te6edf3is_debug Tff7b72else Te6edf3RELEASE_IDTb4b4b4,
Ta5d6ff"Ta5d6ffurlTa5d6ff"Tb4b4b4: Te6edf3REPO_URLTb4b4b4,
Ta5d6ff"Ta5d6ffauthorTa5d6ff"Tb4b4b4: Ta5d6ff"Ta5d6ffmeshtasticTa5d6ff"Tb4b4b4,
Ta5d6ff"Ta5d6ffnameTa5d6ff"Tb4b4b4: Te6edf3nameTb4b4b4,
Ta5d6ff"Ta5d6ffadditionalSettingsTa5d6ff"Tb4b4b4: Te6edf3jsonTff7b72.Td2a8ffdumpsTb4b4b4(Te6edf3settingsTb4b4b4, Te6edf3separatorsTff7b72=Tb4b4b4(Ta5d6ff"Ta5d6ff,Ta5d6ff"Tb4b4b4, Ta5d6ff"Ta5d6ff:Ta5d6ff"Tb4b4b4)Tb4b4b4)Tb4b4b4,
Tb4b4b4}


Tff7b72def Td2a8ffdeep_linkTb4b4b4(Te6edf3channelTb4b4b4, Te6edf3flavor_keyTb4b4b4)Tb4b4b4:
Te6edf3blob Tff7b72= Te6edf3jsonTff7b72.Td2a8ffdumpsTb4b4b4(Te6edf3config_forTb4b4b4(Te6edf3channelTb4b4b4, Te6edf3flavor_keyTb4b4b4)Tb4b4b4, Te6edf3separatorsTff7b72=Tb4b4b4(Ta5d6ff"Ta5d6ff,Ta5d6ff"Tb4b4b4, Ta5d6ff"Ta5d6ff:Ta5d6ff"Tb4b4b4)Tb4b4b4)
T8b949e# Only the JSON payload is percent-encoded; the scheme prefix stays literal.
Tff7b72return Ta5d6fffTa5d6ff"Tffd700{Te6edf3REDIRECTTffd700}Ta5d6ffobtainium://app/Tffd700{Te6edf3quoteTb4b4b4(Te6edf3blobTb4b4b4, Te6edf3safeTff7b72=Ta5d6ff'Ta5d6ff'Tb4b4b4)Tffd700}Ta5d6ff"


Tff7b72def Td2a8ffrender_tableTb4b4b4(Te6edf3channelsTff7b72=Tff7b72NoneTb4b4b4, Te6edf3label_ofTff7b72=Tff7b72NoneTb4b4b4)Tb4b4b4:
T8b949e"""Render the marker-delimited link table for `channels` (default: all)."""
Te6edf3channels Tff7b72= Te6edf3channels Tff7b72or Te6edf3CHANNELS
Te6edf3lines Tff7b72= Tb4b4b4[
Te6edf3BEGINTb4b4b4,
Ta5d6ff"Ta5d6ff"Tb4b4b4,
Ta5d6ff"Ta5d6ff| Channel | `google` flavor | `fdroid` flavor |Ta5d6ff"Tb4b4b4,
Ta5d6ff"Ta5d6ff|---|---|---|Ta5d6ff"Tb4b4b4,
Tb4b4b4]
Tff7b72for Te6edf3channel Tff7b72in Te6edf3channelsTb4b4b4:
Te6edf3cells Tff7b72= Ta5d6ff"Ta5d6ff | Ta5d6ff"Tff7b72.Td2a8ffjoinTb4b4b4(
Ta5d6fffTa5d6ff"Ta5d6ff[Add](Tffd700{Te6edf3deep_linkTb4b4b4(Te6edf3channelTb4b4b4, Te6edf3flavor_keyTb4b4b4)Tffd700}Ta5d6ff)Ta5d6ff" Tff7b72for Te6edf3flavor_key Tff7b72in Te6edf3FLAVORS
Tb4b4b4)
Te6edf3label Tff7b72= Te6edf3label_ofTb4b4b4(Te6edf3channelTb4b4b4) Tff7b72if Te6edf3label_of Tff7b72else Te6edf3channelTb4b4b4[Ta5d6ff"Ta5d6fflabelTa5d6ff"Tb4b4b4]
Te6edf3linesTff7b72.Td2a8ffappendTb4b4b4(Ta5d6fffTa5d6ff"Ta5d6ff| Tffd700{Te6edf3labelTffd700}Ta5d6ff | Tffd700{Te6edf3cellsTffd700}Ta5d6ff |Ta5d6ff"Tb4b4b4)
Te6edf3lines Tff7b72+Tff7b72= Tb4b4b4[Ta5d6ff"Ta5d6ff"Tb4b4b4, Te6edf3ENDTb4b4b4]
Tff7b72return Ta5d6ff"Tffea00\nTa5d6ff"Tff7b72.Td2a8ffjoinTb4b4b4(Te6edf3linesTb4b4b4)


Tff7b72def Td2a8ffreplace_blockTb4b4b4(Te6edf3textTb4b4b4, Te6edf3bodyTb4b4b4, Te6edf3beginTff7b72=Te6edf3BEGINTb4b4b4, Te6edf3endTff7b72=Te6edf3ENDTb4b4b4)Tb4b4b4:
T8b949e"""Replace the marker-delimited block in `text` with `body`."""
Te6edf3startTb4b4b4, Te6edf3stop Tff7b72= Te6edf3textTff7b72.Td2a8ffindexTb4b4b4(Te6edf3beginTb4b4b4)Tb4b4b4, Te6edf3textTff7b72.Td2a8ffindexTb4b4b4(Te6edf3endTb4b4b4) Tff7b72+ Tffa657lenTb4b4b4(Te6edf3endTb4b4b4)
Tff7b72return Te6edf3textTb4b4b4[Tb4b4b4:Te6edf3startTb4b4b4] Tff7b72+ Te6edf3body Tff7b72+ Te6edf3textTb4b4b4[Te6edf3stopTb4b4b4:Tb4b4b4]


T8b949e# --- live release data (--refresh only) -------------------------------------


Tff7b72def Td2a8fffetch_releasesTb4b4b4(Tb4b4b4)Tb4b4b4:
Te6edf3request Tff7b72= Te6edf3urllibTff7b72.Td2a8ffrequestTff7b72.Td2a8ffRequestTb4b4b4(
Te6edf3RELEASES_APITb4b4b4, Te6edf3headersTff7b72=Tb4b4b4{Ta5d6ff"Ta5d6ffAcceptTa5d6ff"Tb4b4b4: Ta5d6ff"Ta5d6ffapplication/vnd.github+jsonTa5d6ff"Tb4b4b4}
Tb4b4b4)
T8b949e# Authenticate when a token is present purely for the rate limit; the data is
T8b949e# public either way, so this still works locally with no token.
Te6edf3token Tff7b72= Te6edf3osTff7b72.Td2a8ffenvironTff7b72.Td2a8ffgetTb4b4b4(Ta5d6ff"Ta5d6ffGITHUB_TOKENTa5d6ff"Tb4b4b4)
Tff7b72if Te6edf3tokenTb4b4b4:
Te6edf3requestTff7b72.Td2a8ffadd_headerTb4b4b4(Ta5d6ff"Ta5d6ffAuthorizationTa5d6ff"Tb4b4b4, Ta5d6fffTa5d6ff"Ta5d6ffBearer Tffd700{Te6edf3tokenTffd700}Ta5d6ff"Tb4b4b4)
Tff7b72with Te6edf3urllibTff7b72.Td2a8ffrequestTff7b72.Td2a8ffurlopenTb4b4b4(Te6edf3requestTb4b4b4, Te6edf3timeoutTff7b72=T79c0ff60Tb4b4b4) Tff7b72as Te6edf3responseTb4b4b4:
Tff7b72return Te6edf3jsonTff7b72.Td2a8ffloadTb4b4b4(Te6edf3responseTb4b4b4)


Tff7b72def Td2a8ffresolve_releaseTb4b4b4(Te6edf3releasesTb4b4b4, Te6edf3channelTb4b4b4)Tb4b4b4:
T8b949e"""The release a channel's filters select, or None if that channel is empty.

Mirrors the subset of Obtainium's selection we rely on: honour
includePrereleases, apply the release-title filter, skip drafts, and take the
newest match. Obtainium walks its own sorted list, but for a published-channel
probe "newest title match" is the same answer — confirmed on-device.
"""
Te6edf3settings Tff7b72= Te6edf3channelTb4b4b4[Ta5d6ff"Ta5d6ffsettingsTa5d6ff"Tb4b4b4]
Te6edf3include_prereleases Tff7b72= Te6edf3settingsTff7b72.Td2a8ffgetTb4b4b4(Ta5d6ff"Ta5d6ffincludePrereleasesTa5d6ff"Tb4b4b4, Tff7b72FalseTb4b4b4)
Te6edf3title_filter Tff7b72= Te6edf3settingsTff7b72.Td2a8ffgetTb4b4b4(Ta5d6ff"Ta5d6fffilterReleaseTitlesByRegExTa5d6ff"Tb4b4b4)
Te6edf3matches Tff7b72= Tb4b4b4[Tb4b4b4]
Tff7b72for Te6edf3release Tff7b72in Te6edf3releasesTb4b4b4:
Tff7b72if Te6edf3releaseTff7b72.Td2a8ffgetTb4b4b4(Ta5d6ff"Ta5d6ffdraftTa5d6ff"Tb4b4b4)Tb4b4b4:
Tff7b72continue
Tff7b72if Te6edf3releaseTff7b72.Td2a8ffgetTb4b4b4(Ta5d6ff"Ta5d6ffprereleaseTa5d6ff"Tb4b4b4) Tff7b72and Tff7b72not Te6edf3include_prereleasesTb4b4b4:
Tff7b72continue
Te6edf3title Tff7b72= Tb4b4b4(Te6edf3releaseTff7b72.Td2a8ffgetTb4b4b4(Ta5d6ff"Ta5d6ffnameTa5d6ff"Tb4b4b4) Tff7b72or Te6edf3releaseTff7b72.Td2a8ffgetTb4b4b4(Ta5d6ff"Ta5d6fftag_nameTa5d6ff"Tb4b4b4) Tff7b72or Ta5d6ff"Ta5d6ff"Tb4b4b4)Tff7b72.Td2a8ffstripTb4b4b4(Tb4b4b4)
Tff7b72if Te6edf3title_filter Tff7b72and Tff7b72not Te6edf3reTff7b72.Td2a8ffsearchTb4b4b4(Te6edf3title_filterTb4b4b4, Te6edf3titleTb4b4b4)Tb4b4b4:
Tff7b72continue
Te6edf3matchesTff7b72.Td2a8ffappendTb4b4b4(Te6edf3releaseTb4b4b4)
Tff7b72if Tff7b72not Te6edf3matchesTb4b4b4:
Tff7b72return Tff7b72None
Tff7b72return Tffa657maxTb4b4b4(Te6edf3matchesTb4b4b4, Te6edf3keyTff7b72=Tff7b72lambda Te6edf3rTb4b4b4: Te6edf3rTff7b72.Td2a8ffgetTb4b4b4(Ta5d6ff"Ta5d6ffpublished_atTa5d6ff"Tb4b4b4) Tff7b72or Ta5d6ff"Ta5d6ff"Tb4b4b4)


Tff7b72def Td2a8ffmatching_assetsTb4b4b4(Te6edf3releaseTb4b4b4, Te6edf3channelTb4b4b4, Te6edf3flavor_keyTb4b4b4)Tb4b4b4:
T8b949e"""Asset names in `release` that this channel/flavor's apkFilterRegEx selects."""
Te6edf3pattern Tff7b72= Te6edf3jsonTff7b72.Td2a8ffloadsTb4b4b4(Te6edf3config_forTb4b4b4(Te6edf3channelTb4b4b4, Te6edf3flavor_keyTb4b4b4)Tb4b4b4[Ta5d6ff"Ta5d6ffadditionalSettingsTa5d6ff"Tb4b4b4]Tb4b4b4)Tb4b4b4[
Ta5d6ff"Ta5d6ffapkFilterRegExTa5d6ff"
Tb4b4b4]
Tff7b72return Tb4b4b4[
Te6edf3assetTb4b4b4[Ta5d6ff"Ta5d6ffnameTa5d6ff"Tb4b4b4]
Tff7b72for Te6edf3asset Tff7b72in Te6edf3releaseTff7b72.Td2a8ffgetTb4b4b4(Ta5d6ff"Ta5d6ffassetsTa5d6ff"Tb4b4b4, Tb4b4b4[Tb4b4b4]Tb4b4b4)
Tff7b72if Te6edf3assetTb4b4b4[Ta5d6ff"Ta5d6ffnameTa5d6ff"Tb4b4b4]Tff7b72.Td2a8fflowerTb4b4b4(Tb4b4b4)Tff7b72.Td2a8ffendswithTb4b4b4(Tb4b4b4(Ta5d6ff"Ta5d6ff.apkTa5d6ff"Tb4b4b4, Ta5d6ff"Ta5d6ff.xapkTa5d6ff"Tb4b4b4, Ta5d6ff"Ta5d6ff.apkmTa5d6ff"Tb4b4b4, Ta5d6ff"Ta5d6ff.apksTa5d6ff"Tb4b4b4)Tb4b4b4)
Tff7b72and Te6edf3reTff7b72.Td2a8ffsearchTb4b4b4(Te6edf3patternTb4b4b4, Te6edf3assetTb4b4b4[Ta5d6ff"Ta5d6ffnameTa5d6ff"Tb4b4b4]Tb4b4b4)
Tb4b4b4]


Tff7b72def Td2a8ffprobeTb4b4b4(Te6edf3releasesTb4b4b4)Tb4b4b4:
T8b949e"""Resolve every channel/flavor against live releases.

Returns (rows, problems): rows feed the generated status table, problems are
regexes that no longer match anything in a release that does exist — i.e. the
release assets were renamed and these configs are broken.
"""
Te6edf3rowsTb4b4b4, Te6edf3problems Tff7b72= Tb4b4b4[Tb4b4b4]Tb4b4b4, Tb4b4b4[Tb4b4b4]
Tff7b72for Te6edf3channel Tff7b72in Te6edf3CHANNELSTb4b4b4:
Te6edf3release Tff7b72= Te6edf3resolve_releaseTb4b4b4(Te6edf3releasesTb4b4b4, Te6edf3channelTb4b4b4)
Te6edf3counts Tff7b72= Tb4b4b4{Tb4b4b4}
Tff7b72if Te6edf3release Tff7b72is Tff7b72not Tff7b72NoneTb4b4b4:
Tff7b72for Te6edf3flavor_key Tff7b72in Te6edf3FLAVORSTb4b4b4:
Te6edf3assets Tff7b72= Te6edf3matching_assetsTb4b4b4(Te6edf3releaseTb4b4b4, Te6edf3channelTb4b4b4, Te6edf3flavor_keyTb4b4b4)
Te6edf3countsTb4b4b4[Te6edf3flavor_keyTb4b4b4] Tff7b72= Tffa657lenTb4b4b4(Te6edf3assetsTb4b4b4)
Tff7b72if Tff7b72not Te6edf3assetsTb4b4b4:
Te6edf3problemsTff7b72.Td2a8ffappendTb4b4b4(
Ta5d6fffTa5d6ff"Tffd700{Te6edf3channelTb4b4b4[Ta5d6ff'Ta5d6ffkeyTa5d6ff'Tb4b4b4]Tffd700}Ta5d6ff/Tffd700{Te6edf3flavor_keyTffd700}Ta5d6ff: apkFilterRegEx matched no Ta5d6ff"
Ta5d6fffTa5d6ff"Ta5d6ffAPK in Tffd700{Te6edf3releaseTff7b72.Td2a8ffgetTb4b4b4(Ta5d6ff'Ta5d6fftag_nameTa5d6ff'Tb4b4b4)Tffd700}Ta5d6ff — release assets renamed?Ta5d6ff"
Tb4b4b4)
Te6edf3rowsTff7b72.Td2a8ffappendTb4b4b4(Tb4b4b4{Ta5d6ff"Ta5d6ffchannelTa5d6ff"Tb4b4b4: Te6edf3channelTb4b4b4, Ta5d6ff"Ta5d6ffreleaseTa5d6ff"Tb4b4b4: Te6edf3releaseTb4b4b4, Ta5d6ff"Ta5d6ffcountsTa5d6ff"Tb4b4b4: Te6edf3countsTb4b4b4}Tb4b4b4)
Tff7b72return Te6edf3rowsTb4b4b4, Te6edf3problems


Tff7b72def Td2a8ffrender_statusTb4b4b4(Te6edf3rowsTb4b4b4)Tb4b4b4:
T8b949e"""The live channel table. README only — never the archived/bundled guide."""
Te6edf3lines Tff7b72= Tb4b4b4[Te6edf3STATUS_BEGINTb4b4b4, Ta5d6ff"Ta5d6ff"Tb4b4b4, Ta5d6ff"Ta5d6ff| Channel | Currently | Released |Ta5d6ff"Tb4b4b4, Ta5d6ff"Ta5d6ff|---|---|---|Ta5d6ff"Tb4b4b4]
Tff7b72for Te6edf3row Tff7b72in Te6edf3rowsTb4b4b4:
Te6edf3channelTb4b4b4, Te6edf3release Tff7b72= Te6edf3rowTb4b4b4[Ta5d6ff"Ta5d6ffchannelTa5d6ff"Tb4b4b4]Tb4b4b4, Te6edf3rowTb4b4b4[Ta5d6ff"Ta5d6ffreleaseTa5d6ff"Tb4b4b4]
Te6edf3label Tff7b72= Te6edf3README_LABELSTff7b72.Td2a8ffgetTb4b4b4(Te6edf3channelTb4b4b4[Ta5d6ff"Ta5d6ffkeyTa5d6ff"Tb4b4b4]Tb4b4b4, Te6edf3channelTb4b4b4[Ta5d6ff"Ta5d6fflabelTa5d6ff"Tb4b4b4]Tb4b4b4)
Tff7b72if Te6edf3release Tff7b72is Tff7b72NoneTb4b4b4:
Te6edf3linesTff7b72.Td2a8ffappendTb4b4b4(Ta5d6fffTa5d6ff"Ta5d6ff| Tffd700{Te6edf3labelTffd700}Ta5d6ff | *none published right now* | — |Ta5d6ff"Tb4b4b4)
Tff7b72continue
T8b949e# Snapshot is rebuilt per push, so its tag is not a useful "version".
Tff7b72if Te6edf3channelTff7b72.Td2a8ffgetTb4b4b4(Ta5d6ff"Ta5d6ffdebugTa5d6ff"Tb4b4b4)Tb4b4b4:
Te6edf3version Tff7b72= Ta5d6ff"Ta5d6ffrolling, rebuilt on every push to `main`Ta5d6ff"
Tff7b72elseTb4b4b4:
Te6edf3version Tff7b72= Ta5d6fffTa5d6ff"Ta5d6ff`Tffd700{Te6edf3releaseTff7b72.Td2a8ffgetTb4b4b4(Ta5d6ff'Ta5d6fftag_nameTa5d6ff'Tb4b4b4, Ta5d6ff'Ta5d6ff?Ta5d6ff'Tb4b4b4)Tffd700}Ta5d6ff`Ta5d6ff"
Te6edf3date Tff7b72= Tb4b4b4(Te6edf3releaseTff7b72.Td2a8ffgetTb4b4b4(Ta5d6ff"Ta5d6ffpublished_atTa5d6ff"Tb4b4b4) Tff7b72or Ta5d6ff"Ta5d6ff"Tb4b4b4)Tb4b4b4[Tb4b4b4:T79c0ff10Tb4b4b4] Tff7b72or Ta5d6ff"Ta5d6ff—Ta5d6ff"
Te6edf3linesTff7b72.Td2a8ffappendTb4b4b4(Ta5d6fffTa5d6ff"Ta5d6ff| Tffd700{Te6edf3labelTffd700}Ta5d6ff | Tffd700{Te6edf3versionTffd700}Ta5d6ff | Tffd700{Te6edf3dateTffd700}Ta5d6ff |Ta5d6ff"Tb4b4b4)
Te6edf3lines Tff7b72+Tff7b72= Tb4b4b4[Ta5d6ff"Ta5d6ff"Tb4b4b4, Te6edf3STATUS_ENDTb4b4b4]
Tff7b72return Ta5d6ff"Tffea00\nTa5d6ff"Tff7b72.Td2a8ffjoinTb4b4b4(Te6edf3linesTb4b4b4)


Tff7b72def Td2a8ffrender_exportTb4b4b4(Te6edf3flavor_keyTb4b4b4)Tb4b4b4:
Te6edf3by_key Tff7b72= Tb4b4b4{Te6edf3cTb4b4b4[Ta5d6ff"Ta5d6ffkeyTa5d6ff"Tb4b4b4]Tb4b4b4: Te6edf3c Tff7b72for Te6edf3c Tff7b72in Te6edf3CHANNELSTb4b4b4}
T8b949e# One release entry — this file's flavor — plus every debug flavor, which can
T8b949e# all coexist thanks to their per-flavor application-ID suffixes.
Te6edf3apps Tff7b72= Tb4b4b4[Te6edf3config_forTb4b4b4(Te6edf3by_keyTb4b4b4[Te6edf3EXPORT_RELEASE_CHANNELTb4b4b4]Tb4b4b4, Te6edf3flavor_keyTb4b4b4)Tb4b4b4]
Tff7b72for Te6edf3key Tff7b72in Te6edf3EXPORT_DEBUG_CHANNELSTb4b4b4:
Te6edf3apps Tff7b72+Tff7b72= Tb4b4b4[Te6edf3config_forTb4b4b4(Te6edf3by_keyTb4b4b4[Te6edf3keyTb4b4b4]Tb4b4b4, Te6edf3fTb4b4b4) Tff7b72for Te6edf3f Tff7b72in Te6edf3FLAVORSTb4b4b4]
T8b949e# Legacy `{apps, settings}` shape on purpose: Obtainium reads it via the
T8b949e# schemaVersion-absent branch, so we avoid inventing exportedAt/appVersion
T8b949e# provenance for a file no Obtainium install actually produced.
Tff7b72return Te6edf3jsonTff7b72.Td2a8ffdumpsTb4b4b4(Tb4b4b4{Ta5d6ff"Ta5d6ffappsTa5d6ff"Tb4b4b4: Te6edf3appsTb4b4b4, Ta5d6ff"Ta5d6ffsettingsTa5d6ff"Tb4b4b4: Tff7b72NoneTb4b4b4}Tb4b4b4, Te6edf3indentTff7b72=T79c0ff4Tb4b4b4) Tff7b72+ Ta5d6ff"Tffea00\nTa5d6ff"


Tff7b72def Td2a8ffexport_pathTb4b4b4(Te6edf3flavor_keyTb4b4b4)Tb4b4b4:
Tff7b72return Te6edf3OBTAINIUM_DIR Tff7b72/ Ta5d6fffTa5d6ff"Ta5d6ffmeshtastic-obtainium-export-Tffd700{Te6edf3flavor_keyTffd700}Ta5d6ff.jsonTa5d6ff"


Te6edf3README_LABELS Tff7b72= Tb4b4b4{Ta5d6ff"Ta5d6ffstableTa5d6ff"Tb4b4b4: Ta5d6ff"Ta5d6ff**Latest release**Ta5d6ff"Tb4b4b4, Ta5d6ff"Ta5d6ffopenTa5d6ff"Tb4b4b4: Ta5d6ff"Ta5d6ff**Open beta**Ta5d6ff"Tb4b4b4}


Tff7b72def Td2a8fftargetsTb4b4b4(Te6edf3status_rowsTff7b72=Tff7b72NoneTb4b4b4)Tb4b4b4:
T8b949e"""Map of path -> expected full file content.

`status_rows` is supplied only by --refresh; without it the live status block
is left exactly as committed, so --check stays offline and deterministic.
"""
Te6edf3out Tff7b72= Tb4b4b4{Te6edf3export_pathTb4b4b4(Te6edf3kTb4b4b4)Tb4b4b4: Te6edf3render_exportTb4b4b4(Te6edf3kTb4b4b4) Tff7b72for Te6edf3k Tff7b72in Te6edf3FLAVORSTb4b4b4}

T8b949e# The guide is archived per release tag and bundled into the app, so it gets
T8b949e# only the deep links — those derive from constants and never go stale. Live
T8b949e# release state goes in the README alone, which GitHub always renders from the
T8b949e# default branch.
Te6edf3outTb4b4b4[Te6edf3DOCTb4b4b4] Tff7b72= Te6edf3replace_blockTb4b4b4(Te6edf3DOCTff7b72.Td2a8ffread_textTb4b4b4(Tb4b4b4)Tb4b4b4, Te6edf3render_tableTb4b4b4(Tb4b4b4)Tb4b4b4)

Te6edf3readme_channels Tff7b72= Tb4b4b4[Te6edf3c Tff7b72for Te6edf3c Tff7b72in Te6edf3CHANNELS Tff7b72if Te6edf3cTb4b4b4[Ta5d6ff"Ta5d6ffkeyTa5d6ff"Tb4b4b4] Tff7b72in Te6edf3README_CHANNELSTb4b4b4]
Te6edf3readme Tff7b72= Te6edf3replace_blockTb4b4b4(
Te6edf3READMETff7b72.Td2a8ffread_textTb4b4b4(Tb4b4b4)Tb4b4b4,
Te6edf3render_tableTb4b4b4(Te6edf3readme_channelsTb4b4b4, Te6edf3label_ofTff7b72=Tff7b72lambda Te6edf3cTb4b4b4: Te6edf3README_LABELSTb4b4b4[Te6edf3cTb4b4b4[Ta5d6ff"Ta5d6ffkeyTa5d6ff"Tb4b4b4]Tb4b4b4]Tb4b4b4)Tb4b4b4,
Tb4b4b4)
Tff7b72if Te6edf3status_rows Tff7b72is Tff7b72not Tff7b72NoneTb4b4b4:
Te6edf3readme Tff7b72= Te6edf3replace_blockTb4b4b4(
Te6edf3readmeTb4b4b4,
Te6edf3render_statusTb4b4b4(Tb4b4b4[Te6edf3r Tff7b72for Te6edf3r Tff7b72in Te6edf3status_rows Tff7b72if Te6edf3rTb4b4b4[Ta5d6ff"Ta5d6ffchannelTa5d6ff"Tb4b4b4]Tb4b4b4[Ta5d6ff"Ta5d6ffkeyTa5d6ff"Tb4b4b4] Tff7b72in Te6edf3README_CHANNELSTb4b4b4]Tb4b4b4)Tb4b4b4,
Te6edf3STATUS_BEGINTb4b4b4,
Te6edf3STATUS_ENDTb4b4b4,
Tb4b4b4)
Te6edf3outTb4b4b4[Te6edf3READMETb4b4b4] Tff7b72= Te6edf3readme
Tff7b72return Te6edf3out


Tff7b72def Td2a8ffmainTb4b4b4(Tb4b4b4)Tb4b4b4:
Te6edf3parser Tff7b72= Te6edf3argparseTff7b72.Td2a8ffArgumentParserTb4b4b4(Tb4b4b4)
Te6edf3parserTff7b72.Td2a8ffadd_argumentTb4b4b4(
Ta5d6ff"Ta5d6ff--checkTa5d6ff"Tb4b4b4, Te6edf3actionTff7b72=Ta5d6ff"Ta5d6ffstore_trueTa5d6ff"Tb4b4b4, Te6edf3helpTff7b72=Ta5d6ff"Ta5d6ffverify generated files are currentTa5d6ff"
Tb4b4b4)
Te6edf3parserTff7b72.Td2a8ffadd_argumentTb4b4b4(
Ta5d6ff"Ta5d6ff--refreshTa5d6ff"Tb4b4b4,
Te6edf3actionTff7b72=Ta5d6ff"Ta5d6ffstore_trueTa5d6ff"Tb4b4b4,
Te6edf3helpTff7b72=Ta5d6ff"Ta5d6ffalso probe the live releases API and refresh the channel status tableTa5d6ff"Tb4b4b4,
Tb4b4b4)
Te6edf3args Tff7b72= Te6edf3parserTff7b72.Td2a8ffparse_argsTb4b4b4(Tb4b4b4)

Te6edf3status_rows Tff7b72= Tff7b72None
Tff7b72if Te6edf3argsTff7b72.Td2a8ffrefreshTb4b4b4:
Tff7b72tryTb4b4b4:
Te6edf3releases Tff7b72= Te6edf3fetch_releasesTb4b4b4(Tb4b4b4)
Tff7b72except Tb4b4b4(Te6edf3urllibTff7b72.Td2a8fferrorTff7b72.Td2a8ffURLErrorTb4b4b4, Te6edf3urllibTff7b72.Td2a8fferrorTff7b72.Td2a8ffHTTPErrorTb4b4b4, Tf85149TimeoutErrorTb4b4b4) Tff7b72as Te6edf3errTb4b4b4:
T8b949e# A flaky API must not be reported as "configs are broken"; leave the
T8b949e# committed status block alone and let the next run pick it up.
Tffa657printTb4b4b4(Ta5d6fffTa5d6ff"Ta5d6ff::warning::releases API unreachable (Tffd700{Te6edf3errTffd700}Ta5d6ff); skipping --refreshTa5d6ff"Tb4b4b4)
Tff7b72return T79c0ff0
Te6edf3status_rowsTb4b4b4, Te6edf3problems Tff7b72= Te6edf3probeTb4b4b4(Te6edf3releasesTb4b4b4)
Tff7b72for Te6edf3problem Tff7b72in Te6edf3problemsTb4b4b4:
Tffa657printTb4b4b4(Ta5d6fffTa5d6ff"Ta5d6ff::error::Tffd700{Te6edf3problemTffd700}Ta5d6ff"Tb4b4b4)
Tff7b72if Te6edf3problemsTb4b4b4:
Tffa657printTb4b4b4(
Ta5d6ff"Ta5d6ffAn apkFilterRegEx no longer matches the published assets. Either the Ta5d6ff"
Ta5d6ff"Ta5d6ffrelease workflow renamed them, or FLAVORS needs updating.Ta5d6ff"
Tb4b4b4)
Tff7b72return T79c0ff1

Tff7b72tryTb4b4b4:
Te6edf3expected Tff7b72= Te6edf3targetsTb4b4b4(Te6edf3status_rowsTb4b4b4)
Tff7b72except Tf85149ValueErrorTb4b4b4:
Tffa657printTb4b4b4(Ta5d6fffTa5d6ff"Ta5d6fferror: Tffd700{Te6edf3DOCTffd700}Ta5d6ff is missing the BEGIN/END GENERATED markersTa5d6ff"Tb4b4b4)
Tff7b72return T79c0ff1

T8b949e# A missing file counts as drifted rather than crashing, so --check works on
T8b949e# a fresh checkout and the first run can create the export files.
Te6edf3drifted Tff7b72= Tb4b4b4[
Te6edf3p
Tff7b72for Te6edf3pTb4b4b4, Te6edf3content Tff7b72in Te6edf3expectedTff7b72.Td2a8ffitemsTb4b4b4(Tb4b4b4)
Tff7b72if Tff7b72not Te6edf3pTff7b72.Td2a8ffexistsTb4b4b4(Tb4b4b4) Tff7b72or Te6edf3pTff7b72.Td2a8ffread_textTb4b4b4(Tb4b4b4) Tff7b72!= Te6edf3content
Tb4b4b4]

Tff7b72if Te6edf3argsTff7b72.Td2a8ffcheckTb4b4b4:
Tff7b72for Te6edf3path Tff7b72in Te6edf3driftedTb4b4b4:
Tffa657printTb4b4b4(Ta5d6fffTa5d6ff"Ta5d6ffdrifted: Tffd700{Te6edf3pathTff7b72.Td2a8ffrelative_toTb4b4b4(Te6edf3REPO_ROOTTb4b4b4)Tffd700}Ta5d6ff"Tb4b4b4)
Tff7b72if Te6edf3driftedTb4b4b4:
Tffa657printTb4b4b4(Ta5d6ff"Ta5d6ffrun: python3 obtainium/generate-links.pyTa5d6ff"Tb4b4b4)
Tff7b72return T79c0ff1
Tffa657printTb4b4b4(Ta5d6fffTa5d6ff"Ta5d6ffup to date: Tffd700{Tffa657lenTb4b4b4(Te6edf3expectedTb4b4b4)Tffd700}Ta5d6ff generated file(s)Ta5d6ff"Tb4b4b4)
Tff7b72return T79c0ff0

Tff7b72for Te6edf3pathTb4b4b4, Te6edf3content Tff7b72in Te6edf3expectedTff7b72.Td2a8ffitemsTb4b4b4(Tb4b4b4)Tb4b4b4:
Te6edf3pathTff7b72.Td2a8ffwrite_textTb4b4b4(Te6edf3contentTb4b4b4)
Tffa657printTb4b4b4(Ta5d6fffTa5d6ff"Ta5d6ffwrote: Tffd700{Te6edf3pathTff7b72.Td2a8ffrelative_toTb4b4b4(Te6edf3REPO_ROOTTb4b4b4)Tffd700}Ta5d6ff"Tb4b4b4)
Tff7b72return T79c0ff0


Tff7b72if Tff7b72__name__ Tff7b72== Ta5d6ff"Ta5d6ff__main__Ta5d6ff"Tb4b4b4:
Te6edf3sysTff7b72.Td2a8ffexitTb4b4b4(Te6edf3mainTb4b4b4(Tb4b4b4)Tb4b4b4)

Served by rngit 1.5.2 - Generated in 0.2s